(*--------------------------------------------------------
    Holt                  http://coderesearchlabs.com/holt
    by Javier Santo Domingo (j-a-s-d@coderesearchlabs.com)
  --------------------------------------------------------
    processor
  --------------------------------------------------------*)

unit holt_processor;

{$I holt_defines.inc}

interface

uses
  holt_architecture,
  holt_types;

function NewProcessor: IhProcessor;

implementation

uses
  holt_instructions,
  holt_consts;

{ ThProcessor }

type
  ThProcessor = class(TInterfacedObject, IhProcessor, IhExecutionBridge)
  strict private
    FRegisters: ThRegisters;
    FInstructionsSelector: IhInstructionsSelector;
    procedure ResetCommandRegisters(const ACommand: gString);
    function InnerProcess: gBoolean;
  strict protected
    function ExecuteCommand(const ACommand: gString): gBoolean;
    function Execute(
      AEmissionController: IhEmissionController;
      AReportBuilder: IhReportBuilder;
      ATree: IhTree;
      const ACommand: gString
    ): gBoolean;
    function GetLastResult: gString;
  public
    procedure AfterConstruction; override;
  end;

function ThProcessor.GetLastResult: gString;
begin
  result := FRegisters.Command.Result;
end;

function ThProcessor.InnerProcess: gBoolean;

  function performDecode: gBoolean; inline;
  var lCommand: gString;
  begin
    lCommand := FRegisters.Command.Raw;
    while (lCommand <> '') and ((lCommand[1] = ' ') or (lCommand[1] = #9)) do
      Delete(lCommand, 1, 1);
    result := lCommand <> '';
    if result then
      with FRegisters.Command do begin
        Opcode := lCommand[1];
        if length(lCommand) > 1 then begin
          Parameters := lCommand;
          Delete(Parameters, 1, 2);
          while (Parameters <> '') and ((Parameters[1] = ' ') or (lCommand[1] = #9)) do
            Delete(Parameters, 1, 1);
          if (lCommand[2] <> ' ') and (lCommand[2] <> #9) then begin
            Opcode := OPCODE_NAVIGATE;
            Parameters := lCommand;
          end;
        end;
      end;
    with FRegisters do begin
      Flags.Quit := Command.Opcode = OPCODE_QUIT;
      Flags.Parameters := Command.Parameters <> '';
    end;
  end;

  function performExecute: gBoolean; inline;
  begin
    if FRegisters.Flags.Quit then
      result := false
    else begin
      FRegisters.Command.Result :=
        FInstructionsSelector.FetchByOpcode(FRegisters.Command.Opcode).Run(FRegisters);
      result := true;
    end;
  end;

begin
  if performDecode then
    result := performExecute
  else
    result := true;
  if FRegisters.Flags.Debug then begin
    writeln('in: ' + FRegisters.Command.Raw);
    writeln('out: ' + FRegisters.Command.Result);
  end;
end;

procedure ThProcessor.ResetCommandRegisters(const ACommand: gString);
begin
  with FRegisters do begin
    with Flags do begin
      Quit := false;
      Parameters := false;
    end;
    with Command do begin
      Raw := ACommand;
      Opcode := OPCODE_NONE;
      Parameters := '';
      Result := '';
    end;
  end;
end;

function ThProcessor.ExecuteCommand(const ACommand: gString): gBoolean;
begin
  ResetCommandRegisters(ACommand);
  result := InnerProcess;
end;

function ThProcessor.Execute(
    AEmissionController: IhEmissionController; AReportBuilder: IhReportBuilder;
    ATree: IhTree; const ACommand: gString
  ): gBoolean;

  procedure prepareRegisters; inline;
  begin
    with FRegisters do begin
      ExecutionBridge := Self;
      EmissionController := AEmissionController;
      ReportBuilder := AReportBuilder;
      Tree := ATree;
    end;
    ResetCommandRegisters(ACommand);
  end;

begin
  prepareRegisters;
  result := InnerProcess;
end;

procedure ThProcessor.AfterConstruction;
begin
  inherited;
  FInstructionsSelector := NewInstructionsSelector;
  FRegisters.Flags.Debug := false;
end;

function NewProcessor: IhProcessor;
begin
  result := ThProcessor.Create;
end;

end.
